#include <ETH.h>
#include <WiFi.h>
#include <WiFiAP.h>
#include <WiFiClient.h>
#include <WiFiGeneric.h>
#include <WiFiMulti.h>
#include <WiFiScan.h>
#include <WiFiServer.h>
#include <WiFiSTA.h>
#include <WiFiType.h>
#include <WiFiUdp.h>
#include <SPI.h>
#include <U8g2lib.h>
#include <RDA5807.h>
#include <Ticker.h>




//wifi info
char* ssid     = "iron2222";
char* password = "18436099009"; 
//time server
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 28800;
const int daylightOffset_sec = 0;


//显示屏
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 36, /* data=*/ 35, /* cs=*/ 46, /* dc=*/ 33, /* reset=*/ 34);


//收音机
#define ESP32_I2C_SDA 5
#define ESP32_I2C_SCL 4
#define MAX_DELAY_RDS 40   
#define MAX_STATIONS 10     
long rds_elapsed = millis();
uint8_t vol = 1;     
RDA5807 rx;

uint8_t curr_mod = 0;       
void selectDevice(uint8_t dev) 
{
  if (dev == 0) 
  {
    digitalWrite(41, LOW);
    digitalWrite(42, LOW);
  }
  if (dev == 1) 
  {
    digitalWrite(41, HIGH);
    digitalWrite(42, LOW);
  }
  if (dev == 2) 
  {
    digitalWrite(41, HIGH);
    digitalWrite(42, HIGH);
  }
}
uint8_t stations = 0;     
uint16_t fmstation[MAX_STATIONS] = {0};   
/*---搜索收音机的台  从8750~10800 MZH---*/
void searchFM() 
{
  uint16_t i = 0;
  uint8_t num = 0;
  rx.setFrequency(8750);      
  while (i < 210) 
  {
    delay(100);
    if (rx.isStereo() && rx.getRssi() > 30) 
    { 
      fmstation[num++] = findMaxSing(rx.getFrequency(), rx.getRssi());
      //rx.setFrequency(rx.getFrequency()+50);
      if (num >= MAX_STATIONS) 
      return;  
    }
    rx.setFrequencyUp();
    i++;
  }
  for (i = 0; i < MAX_STATIONS; i++) 
  {
    Serial.print(fmstation[i]);
    Serial.print("    ");
  }
  Serial.println("Search over!");
}
/*--优化频段--*/
uint16_t findMaxSing(uint16_t freq, uint8_t rssi) {
  while (rx.isStereo()) 
  {
    rx.setFrequencyUp();
    delay(100);
    if (rx.isStereo() && rx.getRssi() > rssi)
    {
      freq = rx.getFrequency();
      rssi = rx.getRssi();
    }
  }
  return freq;
}
/*-----换台-----*/
void changeStation() 
{
  while (true)
  {
    if (stations == MAX_STATIONS - 1) 
    {
      stations = 0;
      rx.setFrequency(fmstation[stations]);
      return;
    }
    if (fmstation[stations + 1] != 0) 
    {
      rx.setFrequency(fmstation[stations + 1]);
      stations++;
      Serial.println(fmstation[stations]);
      return;
    }
    stations++;
  }
}
/*-----可用的电台-----*/
uint8_t availableStation() 
{
  uint8_t i;
  for (i = 0; i < MAX_STATIONS; i++) 
  {
    if (fmstation[i] == 0) 
    return i;
  }
  return i;
}


//按键
int button1Pin = 1;    
int button2Pin = 2;    
int button3Pin = 3;     
int button4Pin = 6;     

//时间控制
int oldsec = -1;     
String ipaddress;    

//网络播放控制部分
uint8_t netbuf[3][1024];     
uint16_t writep = 0;         
uint16_t readp = 0;           
WiFiClient client;           
bool connstat = false;        
bool iswaitecho = false;      
Ticker flipper;             
uint16_t m_offset = 0;
#define WEBSERVERIP "192.168.43.212"
#define WEBSERVERPORT 80
void onTimer(void) 
{
  if (readp <= writep)  
  dacWrite(17, netbuf[readp % 3][m_offset++]);   
  if (m_offset >= 1024) 
  {
    m_offset = 0;
    readp++;     
  }
}
//连接网络音乐服务器
bool connNetSever() 
{
  uint8_t i = 0;
  while (i < 5)
  { 
    if (client.connect(WEBSERVERIP, WEBSERVERPORT)) {
      connstat = true;
      Serial.println("连接成功");
      return true;
    } 
    else 
    {
      Serial.println("访问失败");
      client.stop(); 
    }
    i++;
    delay(100);
  }
  return false;
}

void setup() 
{
  Serial.begin(115200);  
  u8g2.begin();
  u8g2.firstPage();
  u8g2.clearBuffer();         
  u8g2.setFontDirection(0); 
  u8g2.setFont(u8g2_font_ncenB14_tr);    
  u8g2.setCursor(10, 40);
  u8g2.print("Searching FM");        
  pinMode(41, OUTPUT);
  pinMode(42, OUTPUT);
  Wire.begin(ESP32_I2C_SDA, ESP32_I2C_SCL);
  rx.setup();
  rx.setVolume(vol);
 
  searchFM();          
  rx.setFrequency(fmstation[stations]);
  selectDevice(curr_mod); 
  u8g2.firstPage();
  u8g2.clearBuffer();         
  u8g2.setFontDirection(0);   
  u8g2.setCursor(10, 40);
  u8g2.print("Connecting ");
           
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) 
        delay(500);
   u8g2.print(" CONNECTED");
   u8g2.sendBuffer();
  ipaddress = WiFi.localIP().toString();        
  
  Serial.println(ipaddress.c_str());
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); 

  pinMode(button1Pin, INPUT_PULLUP); 
  pinMode(button2Pin, INPUT_PULLUP);
  pinMode(button3Pin, INPUT_PULLUP);
  pinMode(button4Pin, INPUT_PULLUP);

}
void loop() 
{
  uint16_t num = 0;
  if (digitalRead(button1Pin) == LOW) 
  { 
    delay(200); 
    if (digitalRead(button1Pin) == LOW)
    { 
      if (curr_mod == 2) 
      { 
        client.write('q');
        client.stop(); 
        flipper.detach();
        connstat = false;
      }
      curr_mod = (curr_mod + 1) % 3;      
      selectDevice(curr_mod);
      if (curr_mod == 2) 
      connNetSever();
      oldsec = -1;
      dispSerCustStat();
    }
  }
  //网络音乐连接后 需要从网络上获取数据
  if (curr_mod == 2 && connstat == true) 
  {
    if (iswaitecho == false && (writep - readp) < 2) 
    {
      client.write('n');         
      iswaitecho = true;
    }
    if (writep % 120 == 0) 
    display_Oled();   
    if (client.available()) 
    { 
      num = client.read(netbuf[writep % 3], 1024);
      if (writep == 0 && readp == 0) 
      {
        flipper.attach(0, onTimer);    
      }
      writep++;
      iswaitecho = false;
    }
  } 
  else 
  display_Oled();
  if (curr_mod == 1) 
  {
    if (digitalRead(button2Pin) == LOW) 
    {
      delay(200); 
      if (digitalRead(button2Pin) == LOW) 
      {
        changeStation();
        dispSerCustStat();
        oldsec = -1;
      }
    }

    if (digitalRead(button3Pin) == LOW) 
    { 
      delay(200); 
      if (digitalRead(button3Pin) == LOW) 
      { 
        
        if (vol > 0) vol--;
        rx.setVolume(vol);
        dispSerCustStat();
        oldsec = -1;
      }
    }

    if (digitalRead(button4Pin) == LOW) 
    { 
      delay(200); 
      if (digitalRead(button4Pin) == LOW) 
      { 
        vol++;
        if (vol > 15) vol = 15; 
        rx.setVolume(vol);
        dispSerCustStat();
        oldsec = -1;
      }
    }
  }
}
void dispSerCustStat()
{
  Serial.print("Sour=");
  Serial.print(curr_mod);
  Serial.print("    Station=");
  Serial.print(stations);
  Serial.print(" vol=");
  Serial.println(vol);

}

/*---输出当时时间----*/
void display_Oled() 
{
  struct tm timeinfo;
  char str[64] = {0};
  if (!getLocalTime(&timeinfo)) 
  {
    Serial.println("Failed to obtain time");
    return;
  }
  if (oldsec == timeinfo.tm_sec)    
  return;
  oldsec = timeinfo.tm_sec;
  
  u8g2.firstPage();          
  u8g2.clearBuffer();         
  u8g2.setFontDirection(0);
  if (curr_mod == 0) 
  {   
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.setCursor(25, 20);
    u8g2.print(&timeinfo, "%H:%M:%S");
    u8g2.setFont(u8g2_font_ncenB08_tf);  
    u8g2.setCursor(30, 36);
    u8g2.print(&timeinfo, "%Y/%m/%d");
    u8g2.setCursor(33, 54);
    u8g2.print(ipaddress.c_str());
  } 
  else if (curr_mod == 1)
  { 
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.setCursor(15, 20);
    u8g2.print("FM Radio");
    u8g2.setFont(u8g2_font_ncenB08_tf);  
    u8g2.setCursor(20, 32);
    sprintf(str, "CH:%d/%d", stations + 1,availableStation());
    u8g2.setCursor(15, 46);
    sprintf(str, "Volume: %02d/%d", vol, 15);
    u8g2.print(str);
    u8g2.setCursor(18, 60);
    sprintf(str, "Channel: %.2f MHz", fmstation[stations]/100);
    u8g2.print(str);
  } 
  else if (curr_mod == 2)
  { 
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.setCursor(15, 20);
    u8g2.print("Net Radio");
    u8g2.setFont(u8g2_font_ncenB08_tf);  
    if (connstat == false)
    {
      
      u8g2.setCursor(25, 46);
      u8g2.print("Unconnected");
      u8g2.setCursor(20, 60);
      u8g2.print("CONNECTION FAILED");
    } 
    else 
    {
      u8g2.setCursor(27, 46);
      u8g2.print("connected");
      u8g2.setCursor(20, 60);
      sprintf(str, "%s:%d", WEBSERVERIP, WEBSERVERPORT);
      u8g2.print(str);
    }
  }
  u8g2.sendBuffer();
}
